Serverless FrameworkでResourceNotFoundExceptionを解消する
はじめに
アノテーションの髙嶋です。
私はAWSへのデプロイにはServerless Frameworkを使用しています。
今回はデプロイ時にResourceNotFoundException
が発生してしまったので、それを解消した話を書きます。
発生事象
今回の実行環境は下記のとおりです。
Python:3.9.16 node:v12.22.12 Serverless Framework:3.28.1
Serverless Frameworkのymlは下記のように記述していました。
service: lambda-test provider: name: aws runtime: python3.9 region: ap-northeast-1 functions: testHandler: handler: functions/handler.lambda_handler package: patterns: - /functions/** resources: Resources: ResourceBasePermission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: lambda-test-dev-testHandler Principal: s3.amazonaws.com SourceArn: arn:aws:s3:::${env:BUCKET_NAME} SourceAccount: ${env:AWS_ID}
※ResourceBasePermissionでLambda関数に対して、S3バケットへのPermissionを設定する。
slsのデプロイコマンドを実行したところ、ResourceNotFoundException
が発生し、失敗してしまいました。
・コマンド
sls deploy
※事前に環境変数としてBUCKET_NAME
とAWS_ID
を設定してください
・エラーメッセージ
Error: CREATE_FAILED: ResourceBasePermission (AWS::Lambda::Permission) Function not found: arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:lambda-test-dev-testHandler (Service: AWSLambdaInternal; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx; Proxy: null)
発生原因
前述したエラーメッセージとCloudFormationのログを確認したところ、Lambda関数の作成より前にLambda関数に対するResourceBasePermissionが実行されていました。
Lambda関数がまだないということで404エラーが発生してしまったようです。
解決方法
Lambda関数が作成されたあとにPermission設定が実行されるよう、実行順の制御を追加する必要があります。
後述した修正を実施することで、エラーが解消することを確認しました。
FunctionNameを参照にする(暗黙的な制御)
「発生事象」で記述したymlファイルでは、FunctionNameを実際に作成される名前で指定していました。
そこを!Ref
で指定することで、CloudFormationでの実行順が暗黙的に制御されるようになります。
・ ・ resources: Resources: ResourceBasePermission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: !Ref TestHandlerLambdaFunction Principal: s3.amazonaws.com SourceArn: arn:aws:s3:::${env:BUCKET_NAME} SourceAccount: ${env:AWS_ID}
実行制御に関しては下記を参照ください。
ユーザーガイド(DependsOn 属性)
また、Lambda関数を参照する場合、ymlで記述した名称を基にServerless Frameworkのルールに則った値で設定する必要があります。
今回の場合はtestHandler
→TestHandlerLambdaFunction
となります。
名称のルールに関しては下記を参照ください。
AWS Infrastructure Resources
DependsOnを記述する(明示的な制御)
DependsOnを記述することで、実行順を明示的に制御することもできます。
・ ・ resources: Resources: ResourceBasePermission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: lambda-test-dev-testHandler Principal: s3.amazonaws.com SourceArn: arn:aws:s3:::${env:BUCKET_NAME} SourceAccount: ${env:AWS_ID} DependsOn: - TestHandlerLambdaFunction
ただ、こちらの方法だとfunctionsで定義するLambda関数名が変更になると、FunctionNameの修正も必要になります。
なので、前述したFunctionNameを参照にする方が暗黙的に制御される、かつ、修正箇所を少なくできる、でいいかなと考えます。
今回得た教訓
実は今回のエラーが発生したのは本番リリース時でした。。
開発環境の構築時は
- Lambda関数を作成するデプロイを実施
- Permissionの記述を追加してデプロイを実施
というように2段階で実施していました。
そのため、すでにLambda関数が存在する状態で実施していたためエラーは発生せず、実行順の制御が必要なことに気付けていませんでした。
なので、本番環境へのリリースと同じ手順を開発環境でも試すこと!を改めて認識しました。
アノテーション株式会社について
アノテーション株式会社は、クラスメソッド社のグループ企業として「オペレーション・エクセレンス」を担える企業を目指してチャレンジを続けています。「らしく働く、らしく生きる」のスローガンを掲げ、様々な背景をもつ多様なメンバーが自由度の高い働き方を通してお客様へサービスを提供し続けてきました。現在当社では一緒に会社を盛り上げていただけるメンバーを募集中です。少しでもご興味あれば、アノテーション株式会社WEBサイトをご覧ください。